'use strict';

const uidObj = require('uni-id');

const createConfig = require('uni-config-center');
const uidConfig = createConfig({
	pluginId: 'uni-id'
});

const usepayConfig = createConfig({
	pluginId: 'use-pay'
});

const {
	wxpay
} = require('use-api');

const {
	Controller
} = require('uni-cloud-router');
const dbcmd = uniCloud.database().command;
const $ = dbcmd.aggregate;

module.exports = class DistributionController extends Controller {
	// 提现
	async cashout() {
		let response = {
			code: 1,
			datas: '',
			msg: ''
		};

		response.msg = '当前提现功能未开启，请自行注释或删除后使用';
		return response;

		let start = Date.now();

		// 请求参数
		const req = this.ctx.data;
		let {
			id,
			type,
			content,
			withdraw_type
		} = req;

		const cashoutRes = await this.db.collection('usemall-distributor-cashout')
			.doc(id)
			.get();
		const [cashoutData] = cashoutRes.data;

		if (!(cashoutData && cashoutData._id)) {
			response.msg = `当前提现数据不存在`;
			return response;
		}

		const userRes = await this.db.collection('uni-id-users').doc(cashoutData.create_uid).field({
			wx_openid: true,
			wx_unionid: true
		}).get();
		const [user] = userRes.data;

		if (!(user && user._id)) {
			response.msg = `当前提现用户[uni-id-users]数据不存在`;
			return response;
		}

		const distributorParameterRes = await this.db.collection('usemall-distributor-parameter').limit(1)
			.get();
		const [distributorParameter] = distributorParameterRes.data;

		const fxs_uid = cashoutData.fxs_uid;

		const memberRes = await this.db.collection('usemall-member').doc(fxs_uid).get();
		const [memberData] = memberRes.data;

		if (!(memberData && memberData._id)) {
			response.msg = `当前提现用户数据不存在`;
			return response;
		}

		let openid = '';
		// 获取用户 openid
		if (memberData.member_weixin) {
			// 获取用户 openid，优先取 小程序 -> 微信公众号 -> APP
			openid = memberData.member_weixin.mp || memberData.member_weixin.h5 || memberData.member_weixin.app;
		}

		if (!openid) {
			response.msg = `当前提现用户[openid]数据不存在，需进行微信授权登录后申请提现`;
			return response;
		}

		if (type == '已提现') {
			let trade_no = '';
			let transferRes = {};

			if (cashoutData.fxs_cashout_way == '微信零钱') {
				trade_no = Date.now() + (Math.round(Math.random() * 1000000) + '').padStart(6, '0');

				// 申请提现金额（单位元）
				const cashout_amount = cashoutData.fxs_cashout_amount / 100;
				// 手续费 = 提现金额 * 提现手续费比例 / 100
				const service_charge = cashout_amount * ((distributorParameter.service_charge / 100) || 0) >=
					0.01 ? cashout_amount * ((distributorParameter.service_charge / 100) || 0) : 0;
				// 提现金额 = 提现金额 - 手续费
				const amount = (cashout_amount - service_charge).toFixed(2);

				switch (withdraw_type) {
					case 1: // 商家转账到零钱
						const path = require('path');

						const wxpayConfig = usepayConfig.config('wxpayV3');

						const wxOptions = {
							...wxpayConfig,
							appCertPath: path.resolve(__dirname, wxpayConfig.appCertPath),
							appPrivateKeyPath: path.resolve(__dirname, wxpayConfig.appPrivateKeyPath),
							agent: uniCloud.$provider == 'aliyun'
						}

						const wxpayV3 = new wxpay.v3api(wxOptions);

						const res = await wxpayV3.transferBatches({
							out_batch_no: trade_no,
							batch_name: '零钱提现',
							batch_remark: content,
							total_amount: amount * 100,
							total_num: 1,
							transfer_detail_list: [{
								out_detail_no: trade_no,
								transfer_amount: amount * 100,
								transfer_remark: content,
								openid: openid
							}]
						});
						
						if (res.message) {
							response.msg = res.message;
							return response;
						}

						// 转账数据
						transferRes = res;
						break;
					case 2: // 微信企业付款到零钱
						const url = uidConfig.config('agent.wxpay-transfers');

						const result = await this.curl(url, {
							nestedQuerystring: true,
							method: 'post',
							headers: {
								'Content-Type': 'application/json'
							},
							dataType: 'json',
							data: {
								trade_no: trade_no,
								openid: openid,
								truename: memberData.member_truename,
								check_name: distributorParameter
									.check_name, // 是否校验实名合法性 NO_CHECK、FORCE_CHECK、OPTION_CHECK
								amount: amount * 100, // 提现金额（单位分）
								desc: content
							}
						});

						const wxpayRes = result.data;

						if (wxpayRes.code !== 200) {
							response.msg = wxpayRes.msg || wxpayRes.message;
							return response;
						}

						// 付款数据
						transferRes = wxpayRes.datas;
						break;
				}
			}

			try {
				let money =
					`提现金额${cashoutData.fxs_cashout_amount / 100}，实际到账${cashoutData.fxs_cashout_amount / 100}`;
				if ((cashoutData.fxs_cashout_amount / 100) * ((distributorParameter.service_charge / 100) ||
						0) >= 0.01) {
					money =
						`提现金额${cashoutData.fxs_cashout_amount / 100}，扣除手续费${distributorParameter.service_charge / 100}，实际到账${this.fmtFloat(cashoutData.fxs_cashout_amount / 100 - ((cashoutData.fxs_cashout_amount / 100) * (distributorParameter.service_charge / 100) || 0))}`;
				}

				// 分销提现成功 303
				// 不需要 await，只需发送请求即可
				uniCloud.httpclient.request(`${uidConfig.config('message-notify.url')}/303`, {
					method: 'post',
					headers: {
						'message-notify-key': uidConfig.config('message-notify.key')
					},
					timeout: 30 * 1000,
					data: {
						id: cashoutData._id,
						uid: cashoutData.create_uid,
						openid: openid,
						scene: 303,
						uname: cashoutData.create_uname,
						title: '分销提现已同意',
						money: money,
						way: `${content}`,
						remark: '查看详情'
					},
					contentType: 'json',
					dataType: 'json'
				});
			} catch (e) {
				console.log('message-notify err', e);
			}

			// 提现成功
			// 累计收益金额 fxs_profit_amount += 提现金额
			// 待审提现 fxs_unprofit_amount -= 提现金额
			await this.db.collection('usemall-distributor').doc(fxs_uid).update({
				fxs_profit_amount: this.db.command.inc(cashoutData.fxs_cashout_amount),
				fxs_unprofit_amount: this.db.command.inc(-cashoutData.fxs_cashout_amount),
				version: this.db.command.inc(1)
			});

			let cashoutUpdateObj = {
				payment_no: transferRes.payment_no
			}

			if (withdraw_type == 1) {
				cashoutUpdateObj = {
					payment_no: transferRes.batch_id,
					transfer_status: transferRes.batch_status,
					transfer_time: transferRes.create_time
				};
			}

			await this.db.collection('usemall-distributor-cashout').doc(id).update({
				trade_no: trade_no,
				...cashoutUpdateObj,
				fxs_cashout_desc: content,
				state: type,
				last_modify_time: new Date().getTime(),
				last_modify_uid: this.ctx.auth.uid,
				last_modify_uname: this.ctx.auth.userInfo.username
			});
		} else if (type == '提现失败') {
			try {
				// 分销提现失败 305
				// 不需要 await，只需发送请求即可
				uniCloud.httpclient.request(`${uidConfig.config('message-notify.url')}/305`, {
					method: 'post',
					headers: {
						'message-notify-key': uidConfig.config('message-notify.key')
					},
					timeout: 30 * 1000,
					data: {
						id: cashoutData._id,
						uid: cashoutData.create_uid,
						openid: openid,
						scene: 305,
						uname: cashoutData.create_uname,
						title: '分销提现已拒绝',
						money: `${cashoutData.fxs_cashout_amount / 100}`,
						way: `${content}`,
						remark: '查看详情'
					},
					contentType: 'json',
					dataType: 'json'
				});
			} catch (e) {
				console.log('message-notify err', e);
			}

			// 提现失败
			// 零钱 fxs_cashout_amount += 提现金额
			// 待审核佣金 fxs_unprofit_amount -= 提现金额
			await this.db.collection('usemall-distributor').doc(fxs_uid).update({
				fxs_cashout_amount: this.db.command.inc(cashoutData.fxs_cashout_amount),
				fxs_unprofit_amount: this.db.command.inc(-cashoutData.fxs_cashout_amount),
				version: this.db.command.inc(1)
			});

			await this.db.collection('usemall-distributor-cashout').doc(id).update({
				fxs_cashout_fail: content,
				state: type,
				last_modify_time: new Date().getTime(),
				last_modify_uid: this.ctx.auth.uid,
				last_modify_uname: this.ctx.auth.userInfo.username
			});
		}

		await this.db.collection('usemall-distributor-log').add({
			fxs_uid: fxs_uid,
			oper_content: content,
			oper_type: type,
			oper_ip: this.ctx.context.CLIENTIP,
			remark: '',
			version: 1,
			is_delete: 0,
			create_time: new Date().getTime(),
			create_uid: this.ctx.auth.uid,
			create_uname: this.ctx.auth.userInfo.username
		});

		response.datas = '操作成功';

		let end = Date.now();
		console.log(`耗时：${end - start}ms`);
		response.code = 0;
		response.msg = `耗时：${end - start}ms`;
		return response;
	}

	// 查询提现进度
	async getCashoutProgress() {
		let response = {
			code: 1,
			datas: ''
		};

		let start = Date.now();

		// 请求参数
		const req = this.ctx.data;
		let {
			id
		} = req;

		const cashoutRes = await this.db.collection('usemall-distributor-cashout')
			.doc(id)
			.get();
		const [cashoutData] = cashoutRes.data;

		if (!(cashoutData && cashoutData._id)) {
			response.msg = `当前提现数据不存在`;
			return response;
		}

		switch (cashoutData.withdraw_type) {
			case 1:
				const path = require('path');

				const wxpayConfig = usepayConfig.config('wxpayV3');

				const wxOptions = {
					...wxpayConfig,
					appCertPath: path.resolve(__dirname, wxpayConfig.appCertPath),
					appPrivateKeyPath: path.resolve(__dirname, wxpayConfig.appPrivateKeyPath),
					agent: uniCloud.$provider == 'aliyun'
				}

				const wxpayV3 = new wxpay.v3api(wxOptions);

				const res = await wxpayV3.transferBatchesQuery({
					out_batch_no: cashoutData.trade_no
				});
				
				if (res && res.code) {
					response.msg = res.message;
					return response;
				}

				response.datas = res.transfer_batch;
				break;
			case 2:
				// 查询微信企业付款到零钱 agent url
				const url = uidConfig.config('agent.wxpay-transfersQuery');

				const result = await this.curl(url, {
					nestedQuerystring: true,
					method: 'post',
					headers: {
						'Content-Type': 'application/json'
					},
					dataType: 'json',
					data: {
						trade_no: cashoutData.trade_no
					}
				});

				response.datas = result.data.datas;
				break;
		}

		let end = Date.now();
		console.log(`耗时：${end - start}ms`);
		response.code = 0;
		response.msg = `耗时：${end - start}ms`;
		return response;
	}

	// 查询分销商
	async userGet() {
		let response = {
			code: 1,
			datas: [],
			msg: ''
		};

		const start = Date.now();
		const {
			// 总数
			isCount,
			// 分页
			page = 1,
			rows = 10,
			orderby = 'create_time desc',
			// 条件
			member_nickname,
			begin_time,
			end_time
		} = this.ctx.data;

		// 查询条件
		const whereObj = {};

		if (member_nickname) {
			whereObj.member_nickname = new RegExp(this.filterRegexpKey(member_nickname), 'i');
		}

		if (begin_time && end_time) {
			whereObj.create_time = dbcmd.gte(begin_time).and(dbcmd.lte(end_time));
		}

		if (isCount) {
			// 查询总数量
			const countRes = await this.db.collection('usemall-member').where(whereObj).field({
				_id: true
			}).count();
			response.total = countRes.total;
		}

		// 排序规则
		const [field, sort] = orderby.split(' ');
		const userRes = await this.db.collection('usemall-member')
			.where(whereObj)
			.orderBy(field, sort)
			.skip((page - 1) * rows)
			.limit(rows)
			.field({
				member_nickname: true,
				member_headimg: true
			})
			.get();

		const datas = [];
		const ids = userRes.data.map(x => x._id);
		if (ids.length) {
			const subDataRes = await this.db.collection('usemall-distributor')
				.where({
					_id: dbcmd.in(ids)
				})
				.limit(ids.length)
				.get();

			subDataRes.data.forEach(x => {
				const member = userRes.data.find(m => m._id === x._id);
				datas.push({
					...x,
					member
				})
			});
		}
		response.datas = datas;

		const end = Date.now();
		response.code = 0;
		response.duration = `耗时：${end - start}ms`;
		return response;
	}

	// 详情数据
	async detail() {
		let response = {
			code: 1,
			datas: {},
			msg: ''
		};

		const start = Date.now();
		const {
			id
		} = this.ctx.data;

		if (!id) {
			this.throw('查询分销商不存在');
		}

		// 查询分销商
		const distributorRes = await this.db.collection('usemall-distributor')
			.doc(id)
			.field({
				fxs_member_id: true,
				fxs_member_cnt: true,
				fxs_order_cnt: true,
				fxs_profit_amount: true,
				fxs_cashout_amount: true,
				fxs_unprofit_amount: true,
				fxs_unsettled_amount: true,
				create_time: true
			})
			.get();
		const [distributor] = distributorRes.data;

		// 查询分销商用户
		const memberRes = await this.db.collection('usemall-member')
			.doc(distributor.fxs_member_id)
			.field({
				member_headimg: true,
				member_nickname: true,
				member_gender: true,
				member_city: true
			})
			.get();
		const [member] = memberRes.data;

		response.datas.detail = {
			...distributor,
			...member
		}

		// 查询汇总数据
		const totalRes = await this.total();
		response.datas.total = totalRes.datas;

		const end = Date.now();
		console.log(`耗时：${end - start}ms`);
		response.code = 0;
		response.duration = `耗时：${end - start}ms`;
		return response;
	}

	// 汇总数据
	async total() {
		let response = {
			code: 1,
			datas: null,
			msg: ''
		};

		const start = Date.now();
		const {
			id
		} = this.ctx.data;

		// 查询数据数
		const memberRes = this.db.collection('usemall-member').where({
			myfxs_uid: id
		}).field({
			_id: true
		}).count();
		const orderRes = this.db.collection('usemall-order').where(
			dbcmd.and([{
					is_fxs: '是',
					order_pay_state: '已付款'
				},
				dbcmd.or([{
					order_fxs_uid: id
				}, {
					order_fxs_uid2: id
				}])
			])
		).field({
			_id: true
		}).count();
		const distributorCashoutRes = this.db.collection('usemall-distributor-cashout').where({
			fxs_uid: id
		}).field({
			_id: true
		}).count();
		const distributorRecordRes = this.db.collection('usemall-distributor-record').where({
			fxs_uid: id
		}).field({
			_id: true
		}).count();
		const distributorLogRes = this.db.collection('usemall-distributor-log').where({
			fxs_uid: id
		}).field({
			_id: true
		}).count();

		const res = await Promise.all([
			memberRes,
			orderRes,
			distributorCashoutRes,
			distributorRecordRes,
			distributorLogRes
		]);

		response.datas = {
			member_cnt: res[0].total,
			order_cnt: res[1].total,
			withdrawDeposit_cnt: res[2].total,
			record_cnt: res[3].total,
			log_cnt: res[4].total
		};

		const end = Date.now();
		console.log(`耗时：${end - start}ms`);
		response.code = 0;
		response.duration = `耗时：${end - start}ms`;
		return response;
	}

	// 过滤特殊字符
	filterRegexpKey(str) {
		if (!str) return '';

		str += '';

		const arr = ['\\', '$', '(', ')', '*', '+', '.', '[', ']', '?', '^', '{', '}', '|'];

		arr.forEach(x => {
			str = str.replace(new RegExp(`\\${x}`), `\\${x}`);
		});

		return str;
	}

	// 处理精度
	fmtFloat(num) {
		num = parseFloat(num);
		if (isNaN(num)) return num;

		return parseInt(num.toFixed(2) * 100) / 100;
	}
}